﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Media.Imaging;
using UploadClient.Interfaces.Plugins;
using Clipboard = System.Windows.Clipboard;

namespace ClipboardMonitoringPlugin
{
    /// <summary>
    /// This class monitors the clipboard and calls IHost to add new pics to the uploadlist.
    /// </summary>
    public class ClipboardMonitoring : Form, IPlugin
    {
        Configurations config;
        IHost host;
        IntPtr nextClipboardViewer;

        #region IPlugin Members

        public void Init(IHost host)
        {
            this.host = host;
            config = new Configurations(host);
        }

        public void Init(IHost host, IPluginConfig settings)
        {
            this.host = host;
            config = new Configurations(host, settings.Settings);
            if (settings.PluginEnabled) EnablePlugin();
        }

        public IEnumerable<IPluginConfig> GetConfiguration()
        {
            return new IPluginConfig[] { config };
        }

        public void EnablePlugin()
        {
            config.PluginEnabled = true;
            nextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
        }

        public void DisablePlugin()
        {
            config.PluginEnabled = false;
            ChangeClipboardChain(this.Handle, nextClipboardViewer);
        }

        #endregion

        [DllImport("User32.dll")]
        protected static extern int SetClipboardViewer(int hWndNewViewer);

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            try
            {
                ChangeClipboardChain(this.Handle, nextClipboardViewer);
            }
            finally
            {
                base.Dispose(disposing);
            }
        }

        protected override void WndProc(ref Message m)
        {
            // defined in winuser.h
            const int WM_DRAWCLIPBOARD = 0x308;
            const int WM_CHANGECBCHAIN = 0x030D;

            switch (m.Msg)
            {
                case WM_DRAWCLIPBOARD:
                    if (config.PluginEnabled && Clipboard.ContainsImage())
                    {
                        // save screenshot local 
                        string picPath = host.GetTempFileDir();
                        string pic = string.Format("{0}\\{1}.png", picPath, DateTime.Now.ToString("MMddyyHmmss"));
                        SaveClipboardImageToFile(pic);
                        host.AddToUploadlist(pic);
                    }

                    SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                    break;

                case WM_CHANGECBCHAIN:
                    if (m.WParam == nextClipboardViewer)
                        nextClipboardViewer = m.LParam;
                    else
                        SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                    break;

                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        /// <summary>
        /// Save Image from clipboard to a png file.
        /// </summary>
        /// <param name="filePath">The path with the filename.</param>
        public static void SaveClipboardImageToFile(string filePath)
        {
            var image = Clipboard.GetImage();
            using (var fileStream = new FileStream(filePath, FileMode.Create))
            {
                BitmapEncoder encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(image));
                encoder.Save(fileStream);
            }
        }
    }
}
